import com.sun.org.apache.bcel.internal.classfile.Synthetic;
import de.javasoft.plaf.synthetica.SyntheticaBlueMoonLookAndFeel;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.Vector;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.SpinnerNumberModel;
import javax.swing.UIManager;

public class MainWindow extends javax.swing.JFrame {
    
    // The connection handler thread
    public Thread server;
    // A static reference to the main window, so other threads can modify it
    public static MainWindow window;
    
    // Number of currently active threads (engaged in processing HTTP requests)
    public static int number_active_threads;
    // Number of currently sleeping threads (waiting for HTTP requests)
    public static int number_sleeping_threads;
    
    public static Vector <HTTPHandler> available_threads;
    
    public static String DEFAULT_INDEX_FILE = "index.html";
    
    public static String SERVER_ROOT = "c:\\servidor\\";
    
    public static int LISTENING_PORT = 8080;
    
    public static int MINIMUM_CONNECTION_POOL = 2;
    
    public static int THRESHOLD_CONNECTION_POOL = 5;
    
    public static int MAXIMUM_CONNECTION_POOL = 10;
    
    public static int CONNECTION_HANDLING_TYPE = 1;
    
     /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    UIManager.setLookAndFeel(new SyntheticaBlueMoonLookAndFeel());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                new MainWindow().setVisible(true);
            }
        });
    }
    
    public MainWindow() {
        initComponents();
        this.setTitle("J3W - Java WWW Server");
        this.setResizable(false);
        this.setLocationRelativeTo(null);
        this.txtLog.setEditable(false);
        this.comboConnectionHandling.removeAllItems();
        this.comboConnectionHandling.addItem(new String("One connection"));
        this.comboConnectionHandling.addItem(new String("Greedy threader"));
        this.comboConnectionHandling.addItem(new String("Connection pool"));
        this.spinnerMinimumConnections.setModel(new SpinnerNumberModel(2,0,10000,1));
        this.spinnerConnectionThreshold.setModel(new SpinnerNumberModel(5,0,10000,1));
        this.spinnerMaximumConnections.setModel(new SpinnerNumberModel(10,0,10000,1));
        this.spinnerListeningPort.setModel(new SpinnerNumberModel(8080,0,100000,1));
        MainWindow.window = this;
        SyntheticaBlueMoonLookAndFeel.setAntiAliasEnabled(true);
        this.number_sleeping_threads = 0;
        this.number_active_threads = 0;
        MainWindow.available_threads = new Vector <HTTPHandler> ();
        loadConfiguration();
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {
        panelConnectionPool = new javax.swing.JPanel();
        labelNetworkTopology = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        spinnerMaximumConnections = new javax.swing.JSpinner();
        jLabel5 = new javax.swing.JLabel();
        spinnerConnectionThreshold = new javax.swing.JSpinner();
        jLabel4 = new javax.swing.JLabel();
        spinnerMinimumConnections = new javax.swing.JSpinner();
        groupNetworkTopology1 = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        txtServerRootFolder = new javax.swing.JTextField();
        comboConnectionHandling = new javax.swing.JComboBox();
        btnExploreRootFolder = new javax.swing.JButton();
        spinnerListeningPort = new javax.swing.JSpinner();
        lbDefaultIndexFile = new javax.swing.JLabel();
        txtDefaultIndexFile = new javax.swing.JTextField();
        groupNetworkTopology2 = new javax.swing.JPanel();
        lbStatus = new javax.swing.JLabel();
        lbSleepingThreads = new javax.swing.JLabel();
        lbActiveThreads = new javax.swing.JLabel();
        btnStart = new javax.swing.JButton();
        groupNetworkTopology3 = new javax.swing.JPanel();
        labelNetworkTopology1 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        txtLog = new javax.swing.JTextPane();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosed(java.awt.event.WindowEvent evt) {
                formWindowClosed(evt);
            }
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        panelConnectionPool.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        panelConnectionPool.setName("f");
        labelNetworkTopology.setFont(new java.awt.Font("Tahoma", 1, 11));
        labelNetworkTopology.setText("Connection  Pool Parameters");

        jLabel6.setText("Maximum connections:");

        spinnerMaximumConnections.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                spinnerMaximumConnectionsStateChanged(evt);
            }
        });

        jLabel5.setText("Connection threshold:");

        spinnerConnectionThreshold.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                spinnerConnectionThresholdStateChanged(evt);
            }
        });

        jLabel4.setText("Minimum connections:");

        spinnerMinimumConnections.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                spinnerMinimumConnectionsStateChanged(evt);
            }
        });

        org.jdesktop.layout.GroupLayout panelConnectionPoolLayout = new org.jdesktop.layout.GroupLayout(panelConnectionPool);
        panelConnectionPool.setLayout(panelConnectionPoolLayout);
        panelConnectionPoolLayout.setHorizontalGroup(
            panelConnectionPoolLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(panelConnectionPoolLayout.createSequentialGroup()
                .add(panelConnectionPoolLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(labelNetworkTopology)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, panelConnectionPoolLayout.createSequentialGroup()
                        .addContainerGap()
                        .add(panelConnectionPoolLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(jLabel6)
                            .add(jLabel5)
                            .add(jLabel4))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(panelConnectionPoolLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(spinnerConnectionThreshold, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)
                            .add(spinnerMaximumConnections, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)
                            .add(spinnerMinimumConnections, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE))))
                .addContainerGap())
        );
        panelConnectionPoolLayout.setVerticalGroup(
            panelConnectionPoolLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(panelConnectionPoolLayout.createSequentialGroup()
                .add(labelNetworkTopology)
                .add(15, 15, 15)
                .add(panelConnectionPoolLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel4)
                    .add(spinnerMinimumConnections, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(panelConnectionPoolLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel5)
                    .add(spinnerConnectionThreshold, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(panelConnectionPoolLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel6)
                    .add(spinnerMaximumConnections, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(25, Short.MAX_VALUE))
        );

        groupNetworkTopology1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        groupNetworkTopology1.setName("f");
        jLabel2.setText("Server Root Folder:");

        jLabel3.setText("Listening Port:");

        jLabel1.setText("Connection Handler:");

        txtServerRootFolder.setText("c:\\servidor\\");
            txtServerRootFolder.setMaximumSize(new java.awt.Dimension(6, 20));

            comboConnectionHandling.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
            comboConnectionHandling.addItemListener(new java.awt.event.ItemListener() {
                public void itemStateChanged(java.awt.event.ItemEvent evt) {
                    comboConnectionHandlingItemStateChanged(evt);
                }
            });

            btnExploreRootFolder.setText("...");
            btnExploreRootFolder.addMouseListener(new java.awt.event.MouseAdapter() {
                public void mousePressed(java.awt.event.MouseEvent evt) {
                    btnExploreRootFolderMousePressed(evt);
                }
            });

            spinnerListeningPort.addChangeListener(new javax.swing.event.ChangeListener() {
                public void stateChanged(javax.swing.event.ChangeEvent evt) {
                    spinnerListeningPortStateChanged(evt);
                }
            });

            lbDefaultIndexFile.setText("Default Index File:");

            txtDefaultIndexFile.addKeyListener(new java.awt.event.KeyAdapter() {
                public void keyPressed(java.awt.event.KeyEvent evt) {
                    txtDefaultIndexFileKeyPressed(evt);
                }
                public void keyTyped(java.awt.event.KeyEvent evt) {
                    txtDefaultIndexFileKeyTyped(evt);
                }
            });

            org.jdesktop.layout.GroupLayout groupNetworkTopology1Layout = new org.jdesktop.layout.GroupLayout(groupNetworkTopology1);
            groupNetworkTopology1.setLayout(groupNetworkTopology1Layout);
            groupNetworkTopology1Layout.setHorizontalGroup(
                groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(groupNetworkTopology1Layout.createSequentialGroup()
                    .addContainerGap()
                    .add(groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                        .add(groupNetworkTopology1Layout.createSequentialGroup()
                            .add(groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                                .add(jLabel2)
                                .add(jLabel1)
                                .add(jLabel3))
                            .add(10, 10, 10)
                            .add(groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                                .add(spinnerListeningPort)
                                .add(comboConnectionHandling, 0, 130, Short.MAX_VALUE)
                                .add(txtDefaultIndexFile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 130, Short.MAX_VALUE)
                                .add(org.jdesktop.layout.GroupLayout.TRAILING, txtServerRootFolder, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 130, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(btnExploreRootFolder, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 27, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                        .add(lbDefaultIndexFile))
                    .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
            );
            groupNetworkTopology1Layout.setVerticalGroup(
                groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(groupNetworkTopology1Layout.createSequentialGroup()
                    .addContainerGap()
                    .add(groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(jLabel1)
                        .add(comboConnectionHandling, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(jLabel2)
                        .add(btnExploreRootFolder)
                        .add(txtServerRootFolder, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(lbDefaultIndexFile)
                        .add(txtDefaultIndexFile, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(groupNetworkTopology1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(spinnerListeningPort, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .add(jLabel3))
                    .addContainerGap(12, Short.MAX_VALUE))
            );

            groupNetworkTopology2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
            groupNetworkTopology2.setName("f");
            lbStatus.setText("Status: Stopped");

            lbSleepingThreads.setText("Sleeping threads: 0");

            lbActiveThreads.setText("Active threads: 0");

            btnStart.setText("Start");
            btnStart.addMouseListener(new java.awt.event.MouseAdapter() {
                public void mousePressed(java.awt.event.MouseEvent evt) {
                    btnStartMousePressed(evt);
                }
            });

            org.jdesktop.layout.GroupLayout groupNetworkTopology2Layout = new org.jdesktop.layout.GroupLayout(groupNetworkTopology2);
            groupNetworkTopology2.setLayout(groupNetworkTopology2Layout);
            groupNetworkTopology2Layout.setHorizontalGroup(
                groupNetworkTopology2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(groupNetworkTopology2Layout.createSequentialGroup()
                    .addContainerGap()
                    .add(groupNetworkTopology2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                        .add(btnStart, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE)
                        .add(lbStatus)
                        .add(lbActiveThreads)
                        .add(lbSleepingThreads))
                    .addContainerGap())
            );
            groupNetworkTopology2Layout.setVerticalGroup(
                groupNetworkTopology2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(groupNetworkTopology2Layout.createSequentialGroup()
                    .addContainerGap()
                    .add(lbStatus)
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(lbActiveThreads)
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(lbSleepingThreads)
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(btnStart, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 20, Short.MAX_VALUE)
                    .addContainerGap())
            );

            groupNetworkTopology3.setBorder(javax.swing.BorderFactory.createEtchedBorder());
            groupNetworkTopology3.setName("f");
            labelNetworkTopology1.setFont(new java.awt.Font("Tahoma", 1, 11));
            labelNetworkTopology1.setText("Log");

            jScrollPane2.setViewportView(txtLog);

            org.jdesktop.layout.GroupLayout groupNetworkTopology3Layout = new org.jdesktop.layout.GroupLayout(groupNetworkTopology3);
            groupNetworkTopology3.setLayout(groupNetworkTopology3Layout);
            groupNetworkTopology3Layout.setHorizontalGroup(
                groupNetworkTopology3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(groupNetworkTopology3Layout.createSequentialGroup()
                    .add(groupNetworkTopology3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                        .add(labelNetworkTopology1)
                        .add(groupNetworkTopology3Layout.createSequentialGroup()
                            .add(10, 10, 10)
                            .add(jScrollPane2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 371, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                    .add(15, 15, 15))
            );
            groupNetworkTopology3Layout.setVerticalGroup(
                groupNetworkTopology3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(groupNetworkTopology3Layout.createSequentialGroup()
                    .add(labelNetworkTopology1)
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(jScrollPane2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 66, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .addContainerGap(16, Short.MAX_VALUE))
            );

            org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
                layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(layout.createSequentialGroup()
                    .add(10, 10, 10)
                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                        .add(layout.createSequentialGroup()
                            .add(groupNetworkTopology1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(panelConnectionPool, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                        .add(layout.createSequentialGroup()
                            .add(groupNetworkTopology2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(groupNetworkTopology3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                    .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
            );
            layout.setVerticalGroup(
                layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(layout.createSequentialGroup()
                    .addContainerGap()
                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                        .add(groupNetworkTopology1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .add(panelConnectionPool, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                        .add(groupNetworkTopology3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .add(groupNetworkTopology2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .addContainerGap())
            );
            pack();
        }// </editor-fold>//GEN-END:initComponents

    private void txtDefaultIndexFileKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtDefaultIndexFileKeyPressed
        MainWindow.DEFAULT_INDEX_FILE = txtDefaultIndexFile.getText();
    }//GEN-LAST:event_txtDefaultIndexFileKeyPressed

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        saveConfiguration();
    }//GEN-LAST:event_formWindowClosing

    private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
        saveConfiguration();
    }//GEN-LAST:event_formWindowClosed

    private void txtDefaultIndexFileKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtDefaultIndexFileKeyTyped
        MainWindow.DEFAULT_INDEX_FILE = txtDefaultIndexFile.getText();
    }//GEN-LAST:event_txtDefaultIndexFileKeyTyped

    private void spinnerMaximumConnectionsStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerMaximumConnectionsStateChanged
        MainWindow.MAXIMUM_CONNECTION_POOL = Integer.parseInt(spinnerMaximumConnections.getValue().toString());
        if(MainWindow.MAXIMUM_CONNECTION_POOL < MainWindow.MINIMUM_CONNECTION_POOL)
        {
            MainWindow.MAXIMUM_CONNECTION_POOL = MainWindow.MINIMUM_CONNECTION_POOL;
            spinnerMaximumConnections.setValue(MainWindow.MAXIMUM_CONNECTION_POOL);
        }
    }//GEN-LAST:event_spinnerMaximumConnectionsStateChanged

    private void spinnerConnectionThresholdStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerConnectionThresholdStateChanged
        MainWindow.THRESHOLD_CONNECTION_POOL = Integer.parseInt(spinnerConnectionThreshold.getValue().toString());
        if(MainWindow.THRESHOLD_CONNECTION_POOL < MainWindow.MINIMUM_CONNECTION_POOL)
        {
            MainWindow.THRESHOLD_CONNECTION_POOL = MainWindow.MINIMUM_CONNECTION_POOL;
            spinnerConnectionThreshold.setValue(MainWindow.THRESHOLD_CONNECTION_POOL);
        }
    }//GEN-LAST:event_spinnerConnectionThresholdStateChanged

    private void spinnerMinimumConnectionsStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerMinimumConnectionsStateChanged
        MainWindow.MINIMUM_CONNECTION_POOL = Integer.parseInt(spinnerMinimumConnections.getValue().toString());
    }//GEN-LAST:event_spinnerMinimumConnectionsStateChanged

    private void spinnerListeningPortStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerListeningPortStateChanged
        MainWindow.LISTENING_PORT = Integer.parseInt(spinnerListeningPort.getValue().toString());
    }//GEN-LAST:event_spinnerListeningPortStateChanged
    
    /**
     * Loads the application's configuration parameters from permanent storage
     */
    public void loadConfiguration()
    {
        BufferedReader reader;
        try {
            reader = new BufferedReader(new FileReader("config.ini"));
            try {
                MainWindow.SERVER_ROOT = reader.readLine();
                MainWindow.DEFAULT_INDEX_FILE = reader.readLine();
                MainWindow.LISTENING_PORT = Integer.parseInt(reader.readLine());
                MainWindow.MINIMUM_CONNECTION_POOL = Integer.parseInt(reader.readLine());
                MainWindow.THRESHOLD_CONNECTION_POOL = Integer.parseInt(reader.readLine());
                MainWindow.MAXIMUM_CONNECTION_POOL = Integer.parseInt(reader.readLine());
                this.txtServerRootFolder.setText(MainWindow.SERVER_ROOT);
                this.txtDefaultIndexFile.setText(MainWindow.DEFAULT_INDEX_FILE);
                this.spinnerListeningPort.setValue(MainWindow.LISTENING_PORT);
                this.spinnerMaximumConnections.setValue(MainWindow.MAXIMUM_CONNECTION_POOL);
                this.spinnerMinimumConnections.setValue(MainWindow.MINIMUM_CONNECTION_POOL);
                reader.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } catch (FileNotFoundException ex) {
            MainWindow.SERVER_ROOT = "c:\\";
            MainWindow.LISTENING_PORT = 8080;
            MainWindow.DEFAULT_INDEX_FILE = "index.html";
            MainWindow.MINIMUM_CONNECTION_POOL = 2;
            MainWindow.THRESHOLD_CONNECTION_POOL = 5;
            MainWindow.MAXIMUM_CONNECTION_POOL = 10;
        }     
    }
    
     /**
     * Saves the application's configuration parameters to permanent storage
     */
    public void saveConfiguration()
    {    
        PrintWriter writer;
        try {
            writer = new PrintWriter(new FileWriter("config.ini"));
            writer.println(MainWindow.SERVER_ROOT);
            writer.println(MainWindow.DEFAULT_INDEX_FILE);
            writer.println(MainWindow.LISTENING_PORT);
            writer.println(MainWindow.MINIMUM_CONNECTION_POOL);
            writer.println(MainWindow.THRESHOLD_CONNECTION_POOL);
            writer.println(MainWindow.MAXIMUM_CONNECTION_POOL);
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    /**
     * Changes the status message in the graphical interface
     * @param statusmsg The status message to display in the graphical interface
     */
    public void setStatus(String statusmsg) {
        this.lbStatus.setText("Status: " + statusmsg);
    }
    
    /**
     * Adds an active thread to the count and updates the count in the interface
     */
    public void addActiveThread() {
        this.number_active_threads++;
        this.lbActiveThreads.setText("Active threads: " + number_active_threads);
    }
    
    /**
     * Removes an active thread from the count and updates the count in the interface
     */
    public void removeActiveThread() {
        this.number_active_threads--;
        this.lbActiveThreads.setText("Active threads: " + number_active_threads);
    }
    
    public void addSleepingThread()
    {
        this.number_sleeping_threads++;
        this.lbSleepingThreads.setText("Sleeping threads: " + number_sleeping_threads);
    }
    
    public void removeSleepingThread()
    {
        this.number_sleeping_threads--;
        this.lbSleepingThreads.setText("Sleeping threads: " + number_sleeping_threads);
    }
        
    /**
     * Enables/Disables the interface controls
     */
    public void setInterfaceState(boolean flag) {
        comboConnectionHandling.setEnabled(flag);
        txtServerRootFolder.setEnabled(flag);
        spinnerListeningPort.setEnabled(flag);
        btnExploreRootFolder.setEnabled(flag);
        spinnerMinimumConnections.setEnabled(flag);
        spinnerMaximumConnections.setEnabled(flag);
        spinnerConnectionThreshold.setEnabled(flag);
        txtDefaultIndexFile.setEnabled(flag);
    }
    
    /**
     * Starts/Stops the HTTP Server
     */
    private void btnStartMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnStartMousePressed
        
        // Start the server
        if(btnStart.getText() == "Start") {
            HTTPHandler.stop = false;
            
            this.btnStart.setText("Stop");
            setStatus("Running");
            setInterfaceState(false);
            
            // Creates the chosen connection handler
            switch(comboConnectionHandling.getSelectedIndex()) {
                case 0:
                    MainWindow.CONNECTION_HANDLING_TYPE = 1;
                    this.server = new NormalConnectionHandler(MainWindow.LISTENING_PORT);
                    break;
                case 1:
                    MainWindow.CONNECTION_HANDLING_TYPE = 2;
                    this.server = new ThreadConnectionHandler(MainWindow.LISTENING_PORT);
                    break;
                case 2:
                    MainWindow.CONNECTION_HANDLING_TYPE = 3;
                    this.server = new ConnectionPoolConnectionHandler(MainWindow.LISTENING_PORT,MINIMUM_CONNECTION_POOL,THRESHOLD_CONNECTION_POOL,MAXIMUM_CONNECTION_POOL);
                    break;
            }
            
            this.server.start();
        } else {
            HTTPHandler.stop = true;
            
            btnStart.setText("Start");
            setStatus("Stopped");
            setInterfaceState(true);
            
            available_threads = new Vector <HTTPHandler> ();
            this.number_sleeping_threads = 1;
            this.number_active_threads = 1;
            removeSleepingThread();
            removeActiveThread();
            
            // Stops the current connection handler
            try {
                switch(comboConnectionHandling.getSelectedIndex()) {
                    case 0:
                        if(!NormalConnectionHandler.server_socket.isClosed())
                            NormalConnectionHandler.server_socket.close();
                        spinnerMinimumConnections.setEnabled(false);
                        spinnerMaximumConnections.setEnabled(false);
                        spinnerConnectionThreshold.setEnabled(false);
                        break;
                    case 1:
                        if(!ThreadConnectionHandler.server_socket.isClosed())
                            ThreadConnectionHandler.server_socket.close();
                        spinnerMinimumConnections.setEnabled(false);
                        spinnerMaximumConnections.setEnabled(false);
                        spinnerConnectionThreshold.setEnabled(false);
                        break;
                    case 2:
                        if(!ConnectionPoolConnectionHandler.server_socket.isClosed())
                            ConnectionPoolConnectionHandler.server_socket.close();
                        break;
                }
            } catch(java.io.IOException e) {
            }
        }
    }//GEN-LAST:event_btnStartMousePressed
    
    /**
     * Handles the interface state changes related to the different choices of connection handlers
     */
    private void comboConnectionHandlingItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboConnectionHandlingItemStateChanged
        boolean enabled = false;
        switch(comboConnectionHandling.getSelectedIndex()) {
            case 0:
                break;
            case 1:
                break;
            case 2:
                enabled = true;
        }
        
        spinnerConnectionThreshold.setEnabled(enabled);
        spinnerMinimumConnections.setEnabled(enabled);
        spinnerMaximumConnections.setEnabled(enabled);
    }//GEN-LAST:event_comboConnectionHandlingItemStateChanged
    
    /**
     * Allows the user to choose the path where the documents are stored
     */
    private void btnExploreRootFolderMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnExploreRootFolderMousePressed
        JFileChooser fc = new JFileChooser();
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int returnVal = fc.showOpenDialog(this);
        
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fc.getSelectedFile();
            String path = file.getAbsolutePath();
            txtServerRootFolder.setText(path);
            MainWindow.SERVER_ROOT = txtServerRootFolder.getText() + "\\";
        }
    }//GEN-LAST:event_btnExploreRootFolderMousePressed
 
    /**
     * Adds a log entry to the log control
     * @param The log message to be added to the log
     */
    public void addLogEntry(String string) {
        Date dt = Calendar.getInstance().getTime();
        txtLog.setText(dt.toString() + " - " + string +  "\n" + txtLog.getText());
    }
    
    public void setSpinnerMinimumValue(int value)
    {
        this.spinnerMinimumConnections.setValue(value);
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnExploreRootFolder;
    private javax.swing.JButton btnStart;
    private javax.swing.JComboBox comboConnectionHandling;
    private javax.swing.JPanel groupNetworkTopology1;
    private javax.swing.JPanel groupNetworkTopology2;
    private javax.swing.JPanel groupNetworkTopology3;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JLabel labelNetworkTopology;
    private javax.swing.JLabel labelNetworkTopology1;
    private javax.swing.JLabel lbActiveThreads;
    private javax.swing.JLabel lbDefaultIndexFile;
    private javax.swing.JLabel lbSleepingThreads;
    private javax.swing.JLabel lbStatus;
    private javax.swing.JPanel panelConnectionPool;
    private javax.swing.JSpinner spinnerConnectionThreshold;
    private javax.swing.JSpinner spinnerListeningPort;
    private javax.swing.JSpinner spinnerMaximumConnections;
    private javax.swing.JSpinner spinnerMinimumConnections;
    private javax.swing.JTextField txtDefaultIndexFile;
    private javax.swing.JTextPane txtLog;
    private javax.swing.JTextField txtServerRootFolder;
    // End of variables declaration//GEN-END:variables
    
}